package me.dr0n3.skyTravel;

import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import ru.tehkode.permissions.PermissionManager;
import ru.tehkode.permissions.bukkit.PermissionsEx;

/**
 * @author dr0n3
 * @date 20.03.2012
 */
public class SkyTravel extends JavaPlugin
{
    static final Logger log = Logger.getLogger("Minecraft");
    public LinkedList<Port> lPorts = new LinkedList<>();
    public LinkedList<Player> lToggles = new LinkedList<>();
    public LinkedList<Player> lPlayersInPorts = new LinkedList<>();
    public LinkedList<Player> lLastPlayersInPorts = new LinkedList<>();
    public HashMap<Player, Location> hmLeftClick = new HashMap<>();
    public HashMap<Player, Location> hmRightClick = new HashMap<>();
    public SkyListener skyListener;
    public String mainDir = "plugins/skyTravel/";
    public FileConfiguration config;
    public PermissionManager permissions;
    public PluginDescriptionFile pdf;
    //##################################
    public int toolID = 0;
    
    @Override
    public void onDisable()
    {
        save();
        writeLog("disabled!", Level.INFO);
    }
    
    @Override
    public void onEnable()
    {
        pdf = this.getDescription();
        
        makeDirectories();
        loadConfig();
        load();
        registerPermissions();
        
        skyListener = new SkyListener(this);
        
        PluginManager pm = this.getServer().getPluginManager();
        pm.registerEvents(skyListener, this);
        
        this.getServer().getScheduler().scheduleAsyncRepeatingTask(this, new Runnable() 
        {
            @Override
            public void run()
            {
                skyListener.updatePlayerLocation();
            }
        }, 60L, 60L);
        
        writeLog("v" + pdf.getVersion() + " enabled!", Level.INFO);
    }
    
    @Override
    public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String args[])
    {        
        if(!(sender instanceof Player))
            return false;
        
        Player player = (Player) sender;
        
        if(cmd.getName().equalsIgnoreCase("port") && permissions.has(player, "skyTravel.port"))
        {
            if(args.length == 0)
                return false;
            else if(args[0].equalsIgnoreCase("toggle"))
            {
                if(args.length != 1)
                {
                    return false;
                }
                else
                {
                    if(lToggles.contains(player))
                    {
                        lToggles.remove(player);
                        sendBackendMessage(player, false, "Du bist nichtmehr im Edit-Mode.");
                        return true;
                    }
                    else
                    {
                        lToggles.add(player);
                        sendBackendMessage(player, false, "Du bist nun im Edit-Mode.");
                        return true;
                    }
                }
                
            }
            else if(args[0].equalsIgnoreCase("new"))
            {
                if(args.length < 2 || args.length > 3)
                {
                    player.sendMessage("Usage: /port new <targetname> [password]");
                    return true;
                }
                else
                {
                    if(hmRightClick.containsKey(player) && hmLeftClick.containsKey(player))
                    {
                        Location x = hmRightClick.get(player);
                        Location y = hmLeftClick.get(player);
                        String pw = (args.length == 2) ? "" : args[2];
                        
                        Port p = new Port(args[1], pw, new Cube(x, y));
                        p.cube.locAppear = new SerializableLocation(player.getLocation());
                        lPorts.add(p);
                        
                        sendBackendMessage(player, false, "Neuer Bereich mit dem Namen " + args[1] + " angelegt. "
                                + "Verlinke ihn mit '/port link'.");
                        return true;
                    }
                    else
                    {
                        sendBackendMessage(player, true, "Bitte bestimme erst die Eckpunkte.");
                        return true;
                    }                    
                }
            }
            else if(args[0].equalsIgnoreCase("delete"))
            {
                if(args.length != 2)
                {
                    player.sendMessage("Usage: /port delete <name>");
                    return true;
                }
                else
                {
                    Port p = getPortByName(args[1]);
                    
                    if(p != null)
                    {
                        lPorts.remove(p);
                        removeReferences(p);
                        sendBackendMessage(player, false, p.name + " erfolgreich entfernt. Verbindungen wurden entfernt.");
                        return true;
                    }
                    else
                    {
                        sendBackendMessage(player, true, "Nicht gefunden.");
                        return true;
                    }
                }
            }
            else if(args[0].equalsIgnoreCase("link"))
            {
                if(args.length != 3)
                {
                    player.sendMessage("Usage: /port link <PortFrom> <PortTo>");
                    return true;
                }
                else
                {
                    Port from = getPortByName(args[1]);
                    Port to = getPortByName(args[2]);
                    
                    if(from == null || to == null)
                    {
                        sendBackendMessage(player, true, "Einer der beiden Ports wurde nicht gefunden.");
                        return true;
                    }
                    
                    from.linkedPort = to;
                    sendBackendMessage(player, false, from.name + " wurde mit " + to.name + " verbunden.");
                    return true;
                }
            }
            else if(args[0].equalsIgnoreCase("list"))
            {
                if(args.length != 1)
                {
                    player.sendMessage("Usage: /port list");
                    return true;
                }
                else
                {
                    int i = 1;
                    
                    player.sendMessage(ChatColor.LIGHT_PURPLE + "##### " + ChatColor.UNDERLINE + "Liste aller Ports" + ChatColor.LIGHT_PURPLE + " #####");
                    
                    if(lPorts.size() == 0)
                    {
                        player.sendMessage(ChatColor.RED + "# Keine Ports gefunden!");
                    }
                    else
                    {
                        for(Port p : lPorts)
                        {
                            if(p.linkedPort != null)
                            {
                                player.sendMessage(ChatColor.LIGHT_PURPLE + "# " + String.valueOf(i) + ". " + p.name + ", Ziel: " + p.linkedPort.name);
                            }
                            else
                            {
                                player.sendMessage(ChatColor.LIGHT_PURPLE + "# " + String.valueOf(i) + ". " + p.name);
                            }
                            
                            i++;
                        }
                    }
                }
            }
        }
        
        if(cmd.getName().equalsIgnoreCase("depart") && permissions.has(player, "skyTravel.depart"))
        {
            if(args.length > 1)
                return false;
            
            if(lPlayersInPorts.contains(player))
            {
                Port p = getPortByPlayer(player);
                
                if(p == null)
                {
                    player.sendMessage(ChatColor.RED + "Du befindest dich auf keinem Schiff.");
                    return true;
                }
                else
                {
                    if(p.pw.equalsIgnoreCase(""))
                    {
                        p.teleportToLinkedPort(player);
                        return true;
                    }
                    else
                    {
                        if(args.length == 0)
                        {
                            player.sendMessage(ChatColor.DARK_RED + "Du musst ein Passwort angeben.");
                            player.sendMessage(ChatColor.DARK_RED + "/depart <Passwort>");
                            return true;
                        }
                        else
                        {
                            if(args[0].equals(p.pw))
                            {
                                p.teleportToLinkedPort(player);
                                return true;
                            }
                            else
                            {
                                player.sendMessage(ChatColor.DARK_RED + "Das Passwort ist falsch.");
                                return true;
                            }
                        }
                    }
                }
            }
            
            return true;
        }
        
        return true;
    }
    
    public void registerPermissions()
    {
        Plugin p = getServer().getPluginManager().getPlugin("PermissionsEx");
        if(p != null)
        {
            if (!this.getServer().getPluginManager().isPluginEnabled(p)) 
            {
                this.getServer().getPluginManager().enablePlugin(p);
            }
            permissions = PermissionsEx.getPermissionManager();
        }     
        else 
            writeLog("PermissionsEx wurde nicht gefunden!", Level.SEVERE);
    }
    
    public void makeDirectories()
    {
        File file = new File(mainDir);
        File configfile = new File(mainDir + "config.yml");
        
        if(!file.exists() || !configfile.exists())
        {
            try
            {
                writeLog("erstelle Verzeichnisse", Level.INFO);
                
                new File(mainDir).mkdir();
                new File(mainDir + "data/").mkdir();
                new File(mainDir + "config.yml").createNewFile();
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
                writeLog("konnte keine Verzeichnisse/Config erstellen", Level.SEVERE);
            }
            
            getConfig().options().copyDefaults(true);
            saveConfig();
        }
    }
    
    public void save()
    {
        try
        {
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(mainDir + "data/ports.dat"));
            oos.writeObject(lPorts);
            oos.close();
            
            writeLog("gespeichert", Level.INFO);
        }
        catch(Exception e)
        {
            e.printStackTrace();
            writeLog("Konnte Daten nicht speichern.", Level.SEVERE);
        }
    }
    
    public void load()
    {
        if(new File(mainDir + "data/ports.dat").exists())
        {
            try
            {
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(mainDir + "data/ports.dat"));
                lPorts = (LinkedList<Port>) ois.readObject();
                ois.close();
                writeLog("geladen", Level.INFO);
            }
            catch(Exception e)
            {
                e.printStackTrace();
                writeLog("Konnte Daten nicht laden.", Level.SEVERE);
            }
        }
    }
    
    public void loadConfig()
    {
        try
        {
            ConfigurationSection csGeneral = getConfig().getConfigurationSection("general");
            
            toolID = csGeneral.getInt("tool");
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            writeLog("konnte Config nicht laden", Level.SEVERE);
        }
    }
    
    public void removeReferences(Port p)
    {
        SerializableLocation appear = p.cube.locAppear;
        
        for(Port po : lPorts)
        {
            if(po.cube.locAppear == appear)
            {
                appear = null;
            }
        }
    }
    
    public Port getPortByPlayer(Player player)
    {
        Port p = null;
        
        for(Port po : lPorts)
        {
            if(po.isInPort(player))
            {
                return po;
            }
        }
        
        return p;
    }
    
    public Port getPortByName(String s)
    {
        for(Port p : lPorts)
        {
            if(p.name.equalsIgnoreCase(s))
            {
                return p;
            }
        }
        
        return null;
    }
    
    public void writeLog(String s, Level level)
    {
        if(level.equals(Level.INFO))
            log.info("[skyRanks] " + s);
        else if(level.equals(Level.WARNING))
            log.warning("[skyRanks] " + s);
        else if(level.equals(Level.SEVERE))
            log.severe("[skyRanks] " + s);
    }
    
    public void sendBackendMessage(Player player, boolean failed, String s)
    {
        if(failed)
        {
            player.sendMessage(ChatColor.RED + "[skyTravel] " + ChatColor.WHITE + s);
        }
        else
        {
            player.sendMessage(ChatColor.GREEN + "[skyTravel] " + ChatColor.WHITE + s);
        }
    }
}
